import { dom, EventHandler, Nodes } from '@knno/dom';
import { splitBarStyle } from './splitBar.css';
import { DATA } from '../symbol';
import { drag } from '../../tools/drag';

interface SplitBarMoveEventDetail {
	distance: number;
}

type SplitBarMoveEvent = CustomEvent<SplitBarMoveEventDetail>;

export interface SplitBarEventMap {
	movestart: PointerEvent;
	move: SplitBarMoveEvent;
	moveend: PointerEvent;
}
export type SplitBarEventKey = keyof SplitBarEventMap;
export type SplitBarEventHandler<T extends SplitBarEventKey, O extends Nodes> = (
	this: O,
	event: SplitBarEventMap[T]
) => void;

export interface SplitBar {
	on<K extends keyof SplitBarEventMap>(
		event: K,
		listener: SplitBarEventHandler<K, this>,
		options?: boolean | AddEventListenerOptions
	): this;
	on<K extends keyof HTMLElementEventMap>(
		event: K,
		listener: EventHandler<K, this>,
		options?: boolean | AddEventListenerOptions
	): this;
	off<K extends keyof SplitBarEventMap>(
		event: K,
		listener: SplitBarEventHandler<K, this>,
		options?: boolean | AddEventListenerOptions
	): this;
	off<K extends keyof HTMLElementEventMap>(
		event: K,
		listener: EventHandler<K, this>,
		options?: boolean | AddEventListenerOptions
	): this;
}

export type SplitBarType = 'horizontal' | 'vertical' | 'none';

export class SplitBar extends Nodes {
	private [DATA]: { overTimer?: number } = {};
	constructor() {
		super(dom.div(splitBarStyle));
		this.on('pointerenter', () => {
			if (this.disabled()) return;
			this[DATA].overTimer = window.setTimeout(() => {
				this[DATA].overTimer = undefined;
				this.addClass('hover');
			}, 64);
		});
		this.on('pointerleave', () => {
			if (typeof this[DATA].overTimer === 'number') {
				clearTimeout(this[DATA].overTimer);
				this[DATA].overTimer = undefined;
			}
			this.removeClass('hover');
		});
		this.on('touchstart', (e) => {
			e.preventDefault();
		});
		this.on('pointerdown', (e) => {
			if (this.disabled()) return;
			e.preventDefault();
			const type = this.type();
			this.emit(new PointerEvent('movestart', e));
			drag(
				this,
				e,
				(evt, distance) => {
					this.emit(
						new CustomEvent('move', {
							detail: {
								distance: type === 'horizontal' ? distance.x : distance.y,
							},
						})
					);
				},
				(e) => {
					const rect = this.elems()[0].getBoundingClientRect();
					if (e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom) {
						this.removeClass('hover');
					}
					this.emit(new PointerEvent('moveend', e));
				}
			);
		});
	}

	disabled(): boolean;
	disabled(value: boolean): this;
	disabled(value?: boolean): boolean | this {
		if (value === undefined) {
			return this.attr('disabled') != null;
		}
		return this.attr('disabled', value);
	}

	type(): SplitBarType;
	type(value: SplitBarType): this;
	type(value?: SplitBarType): this | SplitBarType {
		if (value) {
			this.attr('type', value);
			return this;
		} else {
			const t = this.attr('type') ?? 'none';
			return /^horizontal|vertical$/.test(t) ? (t as SplitBarType) : 'none';
		}
	}
}

export function splitBar(...className: string[]): SplitBar {
	return new SplitBar().addClass(...className);
}
